//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
#include "LigandPDBContact.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <zlib.h>

#include <iostream>
#include <fstream>
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
#define LENGTHTEXT 100
#define MINIMUM_NUMBER_ATOMS 10
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
using namespace std;
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
LigandPDBContact::LigandPDBContact () {
  
  this->listLigands           = new ListLigand ();

  this->filenameDomainIn      = new String ();
  this->domain                = new PDBAtom ();

  this->listContactByLigands  = new TListE <String> ();
    
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
LigandPDBContact::LigandPDBContact (const LigandPDBContact& ligandPDBContact) {
  
  this->listLigands           = new ListLigand (ligandPDBContact.listLigands);

  this->filenameDomainIn      = new String (ligandPDBContact.filenameDomainIn);
  this->domain                = new PDBAtom (ligandPDBContact.domain);

  this->listContactByLigands  = new TListE <String> (ligandPDBContact.listContactByLigands);
    
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
LigandPDBContact::LigandPDBContact (const LigandPDBContact* ligandPDBContact) {
  
  this->listLigands           = new ListLigand (ligandPDBContact->listLigands);

  this->filenameDomainIn      = new String (ligandPDBContact->filenameDomainIn);
  this->domain                = new PDBAtom (ligandPDBContact->domain);

  this->listContactByLigands  = new TListE <String> (ligandPDBContact->listContactByLigands);
    
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
LigandPDBContact::~LigandPDBContact () {
  
  if (this->listLigands)          delete this->listLigands;
  if (this->filenameDomainIn)     delete this->filenameDomainIn;
  if (this->domain)               delete this->domain;
  if (this->listContactByLigands) delete this->listContactByLigands;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void LigandPDBContact::ListLigands (ListLigand* listLigands) {
  
  if (listLigands) *(this->listLigands) = *listLigands;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void LigandPDBContact::FilenameDomainIn (String* filenameDomainIn) {
  
  if (filenameDomainIn) this->filenameDomainIn->In(filenameDomainIn);
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void LigandPDBContact::Domain (PDBAtom* domain) {
  
  if (domain) *(this->domain) = *domain;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void LigandPDBContact::ListContactByLigands (TListE <String>* listContactByLigands) {
  
  if (listContactByLigands) *(this->listContactByLigands) = *listContactByLigands;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
ListLigand* LigandPDBContact::ListLigands (void) {
  
  return this->listLigands;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
String* LigandPDBContact::FilenameDomainIn (void) {
  
  return this->filenameDomainIn;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
PDBAtom* LigandPDBContact::Domain (void) {
  
  return this->domain;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
TListE <String>* LigandPDBContact::ListContactByLigands (void) {
  
  return this->listContactByLigands;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool LigandPDBContact::LoadData (void) {
  
  if (!this->filenameDomainIn          || !this->filenameDomainIn->Length()        ||
      !this->listLigands->FilenameIn() || !this->listLigands->FilenameIn()->Length())
    return false;

  if (!this->listLigands->LoadData())
    return false;

  bool    isGZFile = (this->filenameDomainIn->Contain("gz"))?1:0;

  fstream file;
  gzFile  zipFile;

  char*   buffer = NULL;
  long    length;
  
  String* data   = new String ();

  if (isGZFile) zipFile = gzopen (this->filenameDomainIn->Out(), "rb9");
  else          file.open (this->filenameDomainIn->Out(), fstream::in);

  if (isGZFile) {
    
    if (!zipFile) return false;
    
    gzseek(zipFile, 0, SEEK_END);
    length = gztell(zipFile);
    gzseek(zipFile, 0, SEEK_SET);
    buffer = new char [length + 1];
    gzread(zipFile, buffer, length);
    
  }
  else {
    
    if (!file.is_open()) return false;
    
    file.seekg(0, fstream::end);
    length = file.tellg();
    file.seekg(0, fstream::beg);
    buffer = new char [length + 1];
    file.read (buffer, length);
    
  }

  data->In(buffer); 
  
  if (!this->domain->ReadData(data)) 
    return false;

  if (isGZFile) gzclose(zipFile);
  else          file.close();

  if (buffer) delete buffer;
  if (data)   delete data;

  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool LigandPDBContact::CheckForContacts (double ansgtronDistance) {
  
  if (!this->listLigands                      || !this->listLigands->Ligands() || 
      !this->listLigands->Ligands()->Length() || !this->domain                 ||
      !this->domain->Records()                || !this->domain->Records()->Length())
    return false;
  
  ContactCheck* contactCheck = new ContactCheck ();
  
  contactCheck->Domain(this->domain);
  contactCheck->AnsgtronDistance(ansgtronDistance);
  
  this->listLigands->Ligands()->SetInitial();
  while (this->listLigands->Ligands()->SetNext()) {
    
    Ligand* currentLigand = this->listLigands->Ligands()->GetCurrent();
    
    if (currentLigand->Records()->Length() < MINIMUM_NUMBER_ATOMS) continue;
    
    contactCheck->LigandInt(currentLigand);
    contactCheck->CheckForContacts();
    
    if (contactCheck->HasContact()) {
      
      String* newLigandContact = new String ();
      
      newLigandContact->In(currentLigand->Name());
      newLigandContact->Add("-");
      newLigandContact->Add(currentLigand->Number());
      newLigandContact->Add(";");
      
      contactCheck->Residues()->SetInitial();
      while (contactCheck->Residues()->SetNext()) {
        newLigandContact->Add(contactCheck->Residues()->GetCurrent());
        newLigandContact->Add(",");
      }
      
      this->listContactByLigands->Add(newLigandContact);
      
    }
    
  }
  
  if (contactCheck) delete contactCheck;
  
  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
LigandPDBContact  LigandPDBContact::operator= (const LigandPDBContact& ligandPDBContact) {

  this->filenameDomainIn->In(ligandPDBContact.filenameDomainIn);
  
  *(this->listLigands)          = *(ligandPDBContact.listLigands);
  *(this->domain)               = *(ligandPDBContact.domain);
  *(this->listContactByLigands) = *(ligandPDBContact.listContactByLigands);

  return *this;
    
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//

